package app

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"saltadmin/internal/config"
	"saltadmin/internal/logging"

	"github.com/gin-gonic/gin"
)

// App 应用程序结构体
type App struct {
	config *config.Config
	router *gin.Engine
	server *http.Server
}

// NewApp 创建新的应用程序实例
func NewApp(cfg *config.Config) *App {
	// 设置 Gin 模式
	if cfg.App.Environment == "prod" {
		gin.SetMode(gin.ReleaseMode)
	} else if cfg.App.Debug {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.TestMode)
	}

	// 初始化日志
	logger := logging.NewLogger(cfg.Log)

	// 创建 Gin 引擎
	router := gin.New()
	router.Use(logging.TraceMiddleware())

	// 使用自定义日志中间件
	router.Use(logging.GinLogger(logger))
	router.Use(gin.Recovery())

	// 创建 HTTP 服务器
	server := &http.Server{
		Addr:           fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port),
		Handler:        router,
		ReadTimeout:    time.Duration(cfg.Server.ReadTimeout) * time.Second,
		WriteTimeout:   time.Duration(cfg.Server.WriteTimeout) * time.Second,
		MaxHeaderBytes: cfg.Server.MaxHeaderBytes,
	}

	return &App{
		config: cfg,
		router: router,
		server: server,
	}
}

// Start 启动应用程序
func (a *App) Start() error {
	// 注册路由
	a.registerRoutes()

	// 打印启动信息
	fmt.Printf("启动 %s 服务 (版本: %s, 环境: %s)\n",
		a.config.App.Name,
		a.config.App.Version,
		a.config.App.Environment)
	fmt.Printf("HTTP 服务监听于: %s\n", a.server.Addr)

	// 优雅关闭
	go a.gracefulShutdown()

	// 启动 HTTP 服务
	if err := a.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
		return fmt.Errorf("HTTP 服务启动失败: %w", err)
	}

	return nil
}

// 注册路由
func (a *App) registerRoutes() {
	// API 版本前缀
	v1 := a.router.Group("/api/v1")

	// 健康检查
	v1.GET("/health", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"status":  "ok",
			"app":     a.config.App.Name,
			"version": a.config.App.Version,
		})
	})

	// TODO: 注册其他模块的路由
	// 这里将来会注册各个模块的路由，如：
	// auth.RegisterRoutes(v1)
	// system.RegisterRoutes(v1)
	// user.RegisterRoutes(v1)
	// 等等
}

// 优雅关闭
func (a *App) gracefulShutdown() {
	// 监听中断信号
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit

	log.Println("正在关闭服务器...")

	// 创建一个 5 秒的上下文用于超时
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 尝试优雅关闭服务器
	if err := a.server.Shutdown(ctx); err != nil {
		log.Fatalf("服务器强制关闭: %v", err)
	}

	log.Println("服务器已安全关闭")
}
